package com.stu.interview;

import java.lang.ref.*;
import java.lang.reflect.Field;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * JVM 面试题代码演示
 * 
 * 本类演示了 JVM 相关的面试题，包括：
 * 1. JVM 内存区域和内存溢出
 * 2. 对象引用类型（强、软、弱、虚引用）
 * 3. 垃圾回收机制
 * 4. 类加载和双亲委派模型
 * 5. JVM 内存模型和指令重排序
 * 6. 直接内存的使用
 * 
 * @author 高级软件工程师
 * @version 1.0
 * @since JDK 1.8
 */
public class JavaJVMDemo {

    public static void main(String[] args) {
        System.out.println("=== JVM 面试题演示 ===");
        
        // 1. JVM 内存区域演示
        demonstrateJVMMemoryAreas();
        
        // 2. 对象引用类型演示
        demonstrateReferenceTypes();
        
        // 3. 垃圾回收演示
        demonstrateGarbageCollection();
        
        // 4. 类加载演示
        demonstrateClassLoading();
        
        // 5. JVM 内存模型演示
        demonstrateJVMMemoryModel();
        
        // 6. 直接内存演示
        demonstrateDirectMemory();
        
        // 7. 逃逸分析演示
        demonstrateEscapeAnalysis();
        
        // 8. 常用 JVM 参数说明
        demonstrateJVMParameters();
    }

    /**
     * 演示 JVM 内存区域
     * 面试题：JVM 内存区域分类哪些？堆和栈区别是什么？
     */
    private static void demonstrateJVMMemoryAreas() {
        System.out.println("\n1. === JVM 内存区域演示 ===");
        
        System.out.println("JVM 内存区域分类:");
        System.out.println("1. 程序计数器 (PC Register) - 线程私有，不会 OOM");
        System.out.println("2. 虚拟机栈 (VM Stack) - 线程私有，存储局部变量、操作数栈等");
        System.out.println("3. 本地方法栈 (Native Method Stack) - 线程私有，为 Native 方法服务");
        System.out.println("4. 堆 (Heap) - 线程共享，存储对象实例");
        System.out.println("5. 方法区 (Method Area) - 线程共享，存储类信息、常量、静态变量");
        System.out.println("6. 直接内存 (Direct Memory) - 不属于 JVM 内存，但被 JVM 使用");
        
        // 堆内存演示
        System.out.println("\n堆内存对象创建:");
        HeapObject heapObj = new HeapObject("堆中的对象");
        System.out.println("对象创建在堆中: " + heapObj.getData());
        
        // 栈内存演示
        System.out.println("\n栈内存局部变量:");
        demonstrateStackMemory();
        
        // 方法区演示
        System.out.println("\n方法区静态变量:");
        MethodAreaDemo.staticVariable = "方法区中的静态变量";
        System.out.println("静态变量: " + MethodAreaDemo.staticVariable);
        
        System.out.println("\n堆和栈的区别:");
        System.out.println("堆 (Heap):");
        System.out.println("- 存储对象实例和数组");
        System.out.println("- 线程共享");
        System.out.println("- 垃圾回收的主要区域");
        System.out.println("- 分为新生代和老年代");
        System.out.println("\n栈 (Stack):");
        System.out.println("- 存储局部变量、操作数栈、动态链接、方法出口");
        System.out.println("- 线程私有");
        System.out.println("- 方法调用时创建栈帧，方法结束时销毁");
        System.out.println("- 不需要垃圾回收");
    }

    /**
     * 栈内存演示方法
     */
    private static void demonstrateStackMemory() {
        int localVar = 100; // 局部变量存储在栈中
        String localStr = "栈中的局部变量"; // 引用存储在栈中，对象在堆中
        System.out.println("局部变量 localVar: " + localVar);
        System.out.println("局部变量 localStr: " + localStr);
        
        // 递归调用演示栈深度
        try {
            recursiveMethod(1);
        } catch (StackOverflowError e) {
            System.out.println("栈溢出演示: " + e.getClass().getSimpleName());
        }
    }

    /**
     * 递归方法，用于演示栈溢出
     */
    private static void recursiveMethod(int depth) {
        if (depth > 10) { // 限制递归深度，避免真正的栈溢出
            throw new StackOverflowError("模拟栈溢出");
        }
        recursiveMethod(depth + 1);
    }

    /**
     * 演示对象引用类型
     * 面试题：你怎么理解强、软、弱、虚引用？
     */
    private static void demonstrateReferenceTypes() {
        System.out.println("\n2. === 对象引用类型演示 ===");
        
        // 1. 强引用 (Strong Reference)
        System.out.println("1. 强引用演示:");
        Object strongRef = new Object();
        System.out.println("强引用对象: " + strongRef);
        System.out.println("强引用特点: 只要引用存在，对象就不会被回收");
        
        // 2. 软引用 (Soft Reference)
        System.out.println("\n2. 软引用演示:");
        Object obj = new Object();
        SoftReference<Object> softRef = new SoftReference<>(obj);
        obj = null; // 移除强引用
        
        System.out.println("软引用对象: " + softRef.get());
        System.out.println("软引用特点: 内存不足时会被回收，适合实现缓存");
        
        // 3. 弱引用 (Weak Reference)
        System.out.println("\n3. 弱引用演示:");
        Object weakObj = new Object();
        WeakReference<Object> weakRef = new WeakReference<>(weakObj);
        weakObj = null; // 移除强引用
        
        System.out.println("GC 前弱引用对象: " + weakRef.get());
        System.gc(); // 建议进行垃圾回收
        try {
            Thread.sleep(100); // 等待 GC 完成
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        System.out.println("GC 后弱引用对象: " + weakRef.get());
        System.out.println("弱引用特点: 下次 GC 时一定会被回收");
        
        // 4. 虚引用 (Phantom Reference)
        System.out.println("\n4. 虚引用演示:");
        Object phantomObj = new Object();
        ReferenceQueue<Object> queue = new ReferenceQueue<>();
        PhantomReference<Object> phantomRef = new PhantomReference<>(phantomObj, queue);
        
        System.out.println("虚引用对象: " + phantomRef.get()); // 总是返回 null
        System.out.println("虚引用特点: 无法通过虚引用获取对象，主要用于跟踪对象回收");
        
        phantomObj = null;
        System.gc();
        
        // 检查引用队列
        Reference<?> ref = queue.poll();
        if (ref != null) {
            System.out.println("对象已被回收，虚引用进入队列");
        }
        
        System.out.println("\n引用类型总结:");
        System.out.println("强引用: 普通引用，不会被 GC 回收");
        System.out.println("软引用: 内存不足时回收，适合缓存");
        System.out.println("弱引用: 下次 GC 时回收，适合避免内存泄漏");
        System.out.println("虚引用: 无法获取对象，用于跟踪回收");
    }

    /**
     * 演示垃圾回收机制
     * 面试题：GC 是什么？常用的垃圾回收算法有哪些？
     */
    private static void demonstrateGarbageCollection() {
        System.out.println("\n3. === 垃圾回收机制演示 ===");
        
        System.out.println("垃圾回收算法:");
        System.out.println("1. 标记-清除 (Mark-Sweep): 标记垃圾对象，然后清除");
        System.out.println("   优点: 简单直接");
        System.out.println("   缺点: 产生内存碎片");
        
        System.out.println("\n2. 复制算法 (Copying): 将存活对象复制到另一块内存");
        System.out.println("   优点: 无内存碎片，效率高");
        System.out.println("   缺点: 内存利用率低");
        
        System.out.println("\n3. 标记-整理 (Mark-Compact): 标记后将存活对象向一端移动");
        System.out.println("   优点: 无内存碎片，内存利用率高");
        System.out.println("   缺点: 效率较低");
        
        System.out.println("\n4. 分代收集: 根据对象存活时间采用不同算法");
        System.out.println("   新生代: 复制算法 (对象存活率低)");
        System.out.println("   老年代: 标记-清除或标记-整理 (对象存活率高)");
        
        // 演示对象的生命周期
        System.out.println("\n对象生命周期演示:");
        demonstrateObjectLifecycle();
        
        // 演示内存泄漏
        System.out.println("\n内存泄漏演示:");
        demonstrateMemoryLeak();
    }

    /**
     * 演示对象的生命周期
     */
    private static void demonstrateObjectLifecycle() {
        System.out.println("创建大量临时对象 (新生代):");
        
        for (int i = 0; i < 1000; i++) {
            String temp = new String("临时对象" + i); // 创建临时对象
            // temp 在循环结束后变为垃圾对象
        }
        
        System.out.println("创建长期存活对象 (可能进入老年代):");
        List<String> longLivedObjects = new ArrayList<>();
        for (int i = 0; i < 100; i++) {
            longLivedObjects.add("长期对象" + i);
        }
        
        System.out.println("长期对象数量: " + longLivedObjects.size());
        
        // 建议进行垃圾回收
        System.gc();
        System.out.println("建议 GC 完成");
    }

    /**
     * 演示内存泄漏的常见场景
     */
    private static void demonstrateMemoryLeak() {
        System.out.println("常见内存泄漏场景:");
        
        // 1. 静态集合持有对象引用
        System.out.println("1. 静态集合内存泄漏:");
        MemoryLeakDemo.addToStaticList("泄漏对象1");
        MemoryLeakDemo.addToStaticList("泄漏对象2");
        System.out.println("静态集合大小: " + MemoryLeakDemo.getStaticListSize());
        
        // 2. 监听器未移除
        System.out.println("\n2. 监听器内存泄漏:");
        EventSource eventSource = new EventSource();
        EventListener listener = new EventListener();
        eventSource.addListener(listener);
        System.out.println("添加监听器，如果不移除会导致内存泄漏");
        // eventSource.removeListener(listener); // 应该移除监听器
        
        // 3. ThreadLocal 未清理
        System.out.println("\n3. ThreadLocal 内存泄漏:");
        ThreadLocalDemo.setValue("ThreadLocal 值");
        System.out.println("ThreadLocal 值: " + ThreadLocalDemo.getValue());
        // ThreadLocalDemo.clear(); // 应该清理 ThreadLocal
        
        System.out.println("\n防止内存泄漏的方法:");
        System.out.println("1. 及时移除不需要的对象引用");
        System.out.println("2. 使用弱引用避免强引用循环");
        System.out.println("3. 监听器使用后及时移除");
        System.out.println("4. ThreadLocal 使用后调用 remove()");
        System.out.println("5. 避免在静态集合中存储大量对象");
    }

    /**
     * 演示类加载机制
     * 面试题：什么是类加载器？什么是双亲委派模型？
     */
    private static void demonstrateClassLoading() {
        System.out.println("\n4. === 类加载机制演示 ===");
        
        // 类加载器层次结构
        System.out.println("类加载器层次结构:");
        ClassLoader classLoader = JavaJVMDemo.class.getClassLoader();
        System.out.println("当前类的类加载器: " + classLoader);
        System.out.println("父类加载器: " + classLoader.getParent());
        System.out.println("祖父类加载器: " + classLoader.getParent().getParent());
        
        // 不同类的类加载器
        System.out.println("\n不同类的类加载器:");
        System.out.println("String 类加载器: " + String.class.getClassLoader()); // Bootstrap ClassLoader
        System.out.println("ArrayList 类加载器: " + ArrayList.class.getClassLoader()); // Bootstrap ClassLoader
        System.out.println("自定义类加载器: " + JavaJVMDemo.class.getClassLoader()); // Application ClassLoader
        
        // 双亲委派模型演示
        System.out.println("\n双亲委派模型:");
        System.out.println("1. Bootstrap ClassLoader (启动类加载器)");
        System.out.println("   - 加载 JDK 核心类库 (rt.jar)");
        System.out.println("   - C++ 实现，Java 中显示为 null");
        
        System.out.println("\n2. Extension ClassLoader (扩展类加载器)");
        System.out.println("   - 加载 JDK 扩展库 (ext 目录)");
        System.out.println("   - sun.misc.Launcher$ExtClassLoader");
        
        System.out.println("\n3. Application ClassLoader (应用类加载器)");
        System.out.println("   - 加载应用程序类路径上的类");
        System.out.println("   - sun.misc.Launcher$AppClassLoader");
        
        // 类加载过程
        System.out.println("\n类加载过程:");
        System.out.println("1. 加载 (Loading): 读取 .class 文件到内存");
        System.out.println("2. 链接 (Linking):");
        System.out.println("   - 验证: 验证字节码格式和语义");
        System.out.println("   - 准备: 为静态变量分配内存并设置默认值");
        System.out.println("   - 解析: 将符号引用转换为直接引用");
        System.out.println("3. 初始化 (Initialization): 执行类构造器 <clinit>()");
        
        // 演示类初始化
        System.out.println("\n类初始化演示:");
        System.out.println("访问 ClassInitDemo.staticVar 触发类初始化:");
        System.out.println("静态变量值: " + ClassInitDemo.staticVar);
    }

    /**
     * 演示 JVM 内存模型
     * 面试题：什么是 JVM 内存模型？什么是指令重排序？
     */
    private static void demonstrateJVMMemoryModel() {
        System.out.println("\n5. === JVM 内存模型演示 ===");
        
        System.out.println("JVM 内存模型 (Java Memory Model, JMM):");
        System.out.println("1. 主内存 (Main Memory): 所有线程共享的内存区域");
        System.out.println("2. 工作内存 (Working Memory): 每个线程私有的内存区域");
        System.out.println("3. 内存间交互操作: lock, unlock, read, load, use, assign, store, write");
        
        System.out.println("\nHappens-Before 原则:");
        System.out.println("1. 程序次序规则: 单线程内按程序顺序执行");
        System.out.println("2. 监视器锁规则: unlock 操作 happens-before 后续的 lock 操作");
        System.out.println("3. volatile 变量规则: 写操作 happens-before 后续的读操作");
        System.out.println("4. 线程启动规则: Thread.start() happens-before 线程内的操作");
        System.out.println("5. 线程终止规则: 线程内操作 happens-before Thread.join() 返回");
        System.out.println("6. 传递性: A happens-before B, B happens-before C => A happens-before C");
        
        // volatile 关键字演示
        System.out.println("\nvolatile 关键字演示:");
        VolatileDemo volatileDemo = new VolatileDemo();
        
        // 启动写线程
        Thread writerThread = new Thread(() -> {
            try {
                Thread.sleep(1000);
                volatileDemo.setFlag(true);
                System.out.println("写线程: 设置 flag = true");
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });
        
        // 启动读线程
        Thread readerThread = new Thread(() -> {
            while (!volatileDemo.isFlag()) {
                // 忙等待
            }
            System.out.println("读线程: 检测到 flag = true");
        });
        
        writerThread.start();
        readerThread.start();
        
        try {
            writerThread.join(2000);
            readerThread.join(2000);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        
        System.out.println("\n指令重排序:");
        System.out.println("1. 编译器重排序: 编译时优化指令顺序");
        System.out.println("2. 指令级并行重排序: CPU 执行时重排序");
        System.out.println("3. 内存系统重排序: 缓存和读写缓冲区重排序");
        System.out.println("\n内存屏障防止重排序:");
        System.out.println("1. LoadLoad 屏障: 禁止读操作重排序");
        System.out.println("2. StoreStore 屏障: 禁止写操作重排序");
        System.out.println("3. LoadStore 屏障: 禁止读写操作重排序");
        System.out.println("4. StoreLoad 屏障: 禁止写读操作重排序");
    }

    /**
     * 演示直接内存
     * 面试题：什么是直接内存？怎样访问直接内存？
     */
    private static void demonstrateDirectMemory() {
        System.out.println("\n6. === 直接内存演示 ===");
        
        System.out.println("直接内存特点:");
        System.out.println("1. 不属于 JVM 堆内存，但被 JVM 使用");
        System.out.println("2. 避免了 Java 堆和 Native 堆之间的数据复制");
        System.out.println("3. 分配和回收成本较高");
        System.out.println("4. 不受 JVM 垃圾回收管理");
        
        try {
            // 使用 Unsafe 访问直接内存（仅演示，实际开发不推荐）
            System.out.println("\n直接内存访问演示:");
            
            // 获取 Unsafe 实例
            Field unsafeField = sun.misc.Unsafe.class.getDeclaredField("theUnsafe");
            unsafeField.setAccessible(true);
            sun.misc.Unsafe unsafe = (sun.misc.Unsafe) unsafeField.get(null);
            
            // 分配直接内存
            long memorySize = 1024; // 1KB
            long address = unsafe.allocateMemory(memorySize);
            System.out.println("分配直接内存地址: 0x" + Long.toHexString(address));
            
            // 写入数据
            unsafe.putLong(address, 0x123456789ABCDEFL);
            System.out.println("写入数据: 0x123456789ABCDEF");
            
            // 读取数据
            long value = unsafe.getLong(address);
            System.out.println("读取数据: 0x" + Long.toHexString(value));
            
            // 释放内存
            unsafe.freeMemory(address);
            System.out.println("释放直接内存");
            
        } catch (Exception e) {
            System.out.println("直接内存访问失败: " + e.getMessage());
        }
        
        System.out.println("\n直接内存的应用:");
        System.out.println("1. NIO 的 DirectByteBuffer");
        System.out.println("2. Netty 的零拷贝");
        System.out.println("3. 大数据处理框架");
        System.out.println("4. 高性能缓存系统");
    }

    /**
     * 演示逃逸分析
     * 面试题：什么是逃逸分析？
     */
    private static void demonstrateEscapeAnalysis() {
        System.out.println("\n7. === 逃逸分析演示 ===");
        
        System.out.println("逃逸分析 (Escape Analysis):");
        System.out.println("JVM 分析对象的作用域，判断对象是否会逃逸出方法或线程");
        
        System.out.println("\n逃逸类型:");
        System.out.println("1. 方法逃逸: 对象被返回或传递给其他方法");
        System.out.println("2. 线程逃逸: 对象被其他线程访问");
        
        // 不逃逸的对象 - 可能栈上分配
        System.out.println("\n不逃逸对象演示 (可能栈上分配):");
        for (int i = 0; i < 1000000; i++) {
            noEscapeObject();
        }
        
        // 逃逸的对象 - 必须堆上分配
        System.out.println("逃逸对象演示 (必须堆上分配):");
        EscapeObject escaped = escapeObject();
        System.out.println("逃逸对象: " + escaped.getValue());
        
        System.out.println("\n逃逸分析优化:");
        System.out.println("1. 栈上分配: 不逃逸的对象可能在栈上分配");
        System.out.println("2. 标量替换: 对象被拆分为基本类型变量");
        System.out.println("3. 同步消除: 不逃逸对象的同步操作可以消除");
        
        // 同步消除演示
        System.out.println("\n同步消除演示:");
        synchronizationElimination();
    }

    /**
     * 不逃逸的对象
     */
    private static void noEscapeObject() {
        EscapeObject obj = new EscapeObject("不逃逸");
        // 对象只在方法内使用，不会逃逸
        obj.getValue();
    }

    /**
     * 逃逸的对象
     */
    private static EscapeObject escapeObject() {
        EscapeObject obj = new EscapeObject("逃逸");
        return obj; // 对象被返回，发生逃逸
    }

    /**
     * 同步消除演示
     */
    private static void synchronizationElimination() {
        // 局部对象的同步操作可能被消除
        StringBuffer sb = new StringBuffer();
        sb.append("Hello");
        sb.append(" World");
        System.out.println("同步消除: " + sb.toString());
    }

    /**
     * 演示常用 JVM 参数
     * 面试题：常用的 JVM 参数有哪些？
     */
    private static void demonstrateJVMParameters() {
        System.out.println("\n8. === 常用 JVM 参数说明 ===");
        
        System.out.println("内存相关参数:");
        System.out.println("-Xms: 初始堆大小");
        System.out.println("-Xmx: 最大堆大小");
        System.out.println("-Xmn: 新生代大小");
        System.out.println("-XX:NewRatio: 老年代与新生代比例");
        System.out.println("-XX:SurvivorRatio: Eden 与 Survivor 比例");
        System.out.println("-Xss: 栈大小");
        System.out.println("-XX:MetaspaceSize: 元空间初始大小 (JDK 8+)");
        System.out.println("-XX:MaxMetaspaceSize: 元空间最大大小 (JDK 8+)");
        
        System.out.println("\n垃圾回收相关参数:");
        System.out.println("-XX:+UseSerialGC: 使用串行垃圾回收器");
        System.out.println("-XX:+UseParallelGC: 使用并行垃圾回收器");
        System.out.println("-XX:+UseConcMarkSweepGC: 使用 CMS 垃圾回收器");
        System.out.println("-XX:+UseG1GC: 使用 G1 垃圾回收器");
        System.out.println("-XX:MaxGCPauseMillis: 最大 GC 停顿时间");
        System.out.println("-XX:+PrintGC: 打印 GC 信息");
        System.out.println("-XX:+PrintGCDetails: 打印详细 GC 信息");
        
        System.out.println("\n调试相关参数:");
        System.out.println("-XX:+HeapDumpOnOutOfMemoryError: OOM 时生成堆转储");
        System.out.println("-XX:HeapDumpPath: 堆转储文件路径");
        System.out.println("-XX:+PrintCommandLineFlags: 打印 JVM 参数");
        System.out.println("-XX:+UnlockExperimentalVMOptions: 解锁实验性参数");
        
        System.out.println("\n性能优化参数:");
        System.out.println("-XX:+DoEscapeAnalysis: 启用逃逸分析");
        System.out.println("-XX:+EliminateAllocations: 启用标量替换");
        System.out.println("-XX:+UseBiasedLocking: 启用偏向锁");
        System.out.println("-XX:+UseCompressedOops: 启用压缩指针");
        
        // 获取当前 JVM 信息
        System.out.println("\n当前 JVM 信息:");
        Runtime runtime = Runtime.getRuntime();
        System.out.println("最大内存: " + runtime.maxMemory() / 1024 / 1024 + " MB");
        System.out.println("总内存: " + runtime.totalMemory() / 1024 / 1024 + " MB");
        System.out.println("空闲内存: " + runtime.freeMemory() / 1024 / 1024 + " MB");
        System.out.println("已用内存: " + (runtime.totalMemory() - runtime.freeMemory()) / 1024 / 1024 + " MB");
    }

    // ========== 辅助类 ==========

    /**
     * 堆对象演示类
     */
    static class HeapObject {
        private String data;

        public HeapObject(String data) {
            this.data = data;
        }

        public String getData() {
            return data;
        }
    }

    /**
     * 方法区演示类
     */
    static class MethodAreaDemo {
        public static String staticVariable = "静态变量";
        public static final String CONSTANT = "常量";
    }

    /**
     * 内存泄漏演示类
     */
    static class MemoryLeakDemo {
        private static List<String> staticList = new ArrayList<>();

        public static void addToStaticList(String item) {
            staticList.add(item);
        }

        public static int getStaticListSize() {
            return staticList.size();
        }
    }

    /**
     * 事件源类
     */
    static class EventSource {
        private List<EventListener> listeners = new ArrayList<>();

        public void addListener(EventListener listener) {
            listeners.add(listener);
        }

        public void removeListener(EventListener listener) {
            listeners.remove(listener);
        }
    }

    /**
     * 事件监听器类
     */
    static class EventListener {
        // 监听器实现
    }

    /**
     * ThreadLocal 演示类
     */
    static class ThreadLocalDemo {
        private static ThreadLocal<String> threadLocal = new ThreadLocal<>();

        public static void setValue(String value) {
            threadLocal.set(value);
        }

        public static String getValue() {
            return threadLocal.get();
        }

        public static void clear() {
            threadLocal.remove();
        }
    }

    /**
     * 类初始化演示类
     */
    static class ClassInitDemo {
        public static String staticVar;

        static {
            System.out.println("ClassInitDemo 静态代码块执行");
            staticVar = "静态变量已初始化";
        }
    }

    /**
     * volatile 演示类
     */
    static class VolatileDemo {
        private volatile boolean flag = false;

        public boolean isFlag() {
            return flag;
        }

        public void setFlag(boolean flag) {
            this.flag = flag;
        }
    }

    /**
     * 逃逸分析演示类
     */
    static class EscapeObject {
        private String value;

        public EscapeObject(String value) {
            this.value = value;
        }

        public String getValue() {
            return value;
        }
    }
}